package conf

import (
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"time"

	"gopkg.in/yaml.v2"
)

type config struct {
	Server   serverConfig   `yaml:"server"`
	Database databaseConfig `yaml:"database"`
	Redis    redisConfig    `yaml:"redis"`
	Log      logConfig      `yaml:"log"`
	Jwt      jwtConfig      `yaml:"jwt"`
}

var AppConfig *config

func parseConfig(configPath string, sptr interface{}) {
	//获取当前项目运行路径
	pwd, err := os.Getwd()
	if err != nil {
		panic("获取当前项目运行路径失败" + err.Error())
	}
	data, err := os.ReadFile(filepath.Join(pwd, configPath))
	if err != nil {
		panic("读取配置文件失败:" + err.Error())
	}
	err = yaml.Unmarshal(data, sptr)
	if err != nil {
		panic("解析配置文件失败:" + err.Error())
	}

}

func InitConf(path string) {
	if path == "" {
		fmt.Println("未指定配置文件路径，使用默认路径")
		path = "conf.yaml"
	}
	var cfg = &config{}
	//获取当前项目运行路径
	parseConfig(path, cfg)
	//反射 AppConfig 对于0值设置tag的默认值
	SetDefaultValue(cfg)
	AppConfig = cfg
}
func SetDefaultValue(sptr interface{}) {
	val := reflect.ValueOf(sptr).Elem()
	typ := val.Type()

	for i := 0; i < val.NumField(); i++ {
		fieldVal := val.Field(i)
		fieldTyp := typ.Field(i)

		// 如果字段是结构体类型，递归处理
		if fieldVal.Kind() == reflect.Struct {
			setDefaultForStruct(fieldVal, fieldTyp.Type)
		}
	}
}

func setDefaultForStruct(val reflect.Value, typ reflect.Type) {
	for i := 0; i < val.NumField(); i++ {
		fieldVal := val.Field(i)
		fieldTyp := typ.Field(i)

		// 如果字段是结构体类型，递归处理
		if fieldVal.Kind() == reflect.Struct {
			setDefaultForStruct(fieldVal, fieldTyp.Type)
			continue
		}

		// 只处理可设置的字段
		if fieldVal.CanSet() {
			tag := fieldTyp.Tag.Get("default")
			if tag != "" && isEmptyValue(fieldVal) {
				// 根据字段类型转换默认值
				defaultVal := convertStringToValue(tag, fieldVal.Type())
				if defaultVal.IsValid() {
					fieldVal.Set(defaultVal)
				}
			}
		}
	}
}

func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.String:
		return v.Len() == 0
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Pointer:
		return v.IsNil()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Bool:
		return !v.Bool()
	default:
		return false
	}
}

func convertStringToValue(str string, typ reflect.Type) reflect.Value {
	switch typ.Kind() {
	case reflect.String:
		return reflect.ValueOf(str)
	case reflect.Int:
		if val, err := strconv.Atoi(str); err == nil {
			return reflect.ValueOf(val)
		}
	case reflect.Int64:
		// 特殊处理 time.Duration 类型
		if typ == reflect.TypeOf(time.Duration(0)) {
			if val, err := time.ParseDuration(str); err == nil {
				return reflect.ValueOf(val)
			}
		} else {
			if val, err := strconv.ParseInt(str, 10, 64); err == nil {
				return reflect.ValueOf(val)
			}
		}
	case reflect.Bool:
		if val, err := strconv.ParseBool(str); err == nil {
			return reflect.ValueOf(val)
		}
	}
	return reflect.Value{}
}
